package com.lovezy.platform.borrow.service.impl;

import com.github.pagehelper.Page;
import com.lovezy.platform.borrow.enums.MyGameTypeEnum;
import com.lovezy.platform.borrow.form.HotEditForm;
import com.lovezy.platform.borrow.form.MyGameForm;
import com.lovezy.platform.borrow.form.SetGameForm;
import com.lovezy.platform.borrow.form.SetGameFormManager;
import com.lovezy.platform.borrow.mapper.MyGameMapper;
import com.lovezy.platform.borrow.model.MyGame;
import com.lovezy.platform.borrow.model.MyGameExample;
import com.lovezy.platform.borrow.query.SearchMyGameQuery;
import com.lovezy.platform.borrow.service.MyGameService;
import com.lovezy.platform.borrow.service.MyGameServiceForm;
import com.lovezy.platform.borrow.vo.MyGameVo;
import com.lovezy.platform.core.base.enums.StatusEnum;
import com.lovezy.platform.core.base.enums.TrueOrFalseEnum;
import com.lovezy.platform.core.base.query.Pager;
import com.lovezy.platform.core.base.service.MapperService;
import com.lovezy.platform.core.exception.RequestErrorException;
import com.lovezy.platform.core.exception.ServiceException;
import com.lovezy.platform.core.utils.ArrayUtil;
import com.lovezy.platform.core.valid.ValidatorUtil;
import com.lovezy.platform.filestore.service.FileHelper;
import com.lovezy.platform.shop.service.ShopService;
import com.lovezy.platform.wiki.exception.WikiException;
import com.lovezy.platform.wiki.exception.WikiExceptionEnum;
import com.lovezy.platform.wiki.model.Game;
import com.lovezy.platform.wiki.service.GameService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Optional;
import java.util.function.BiConsumer;

import static com.lovezy.platform.borrow.form.SetGameFormManager.toAddShopGame;
import static com.lovezy.platform.core.utils.ObjectUtil.nonNull;
import static com.lovezy.platform.wiki.exception.WikiExceptionEnum.MYGAME_NOT_FOUND;

/**
 * 我的游戏实现类
 * Created by jin on 2017/11/14.
 */
@Service
public class MyGameServiceImpl extends MapperService<MyGame,Integer,MyGameMapper> implements MyGameService{

    @Autowired
    private GameService gameService;

    @Autowired
    private ShopService shopService;

    @Autowired
    private FileHelper fileHelper;

    @Transactional
    @Override
    public void addMyGame(SetGameForm form) {
        checkDataAndForEach(form, (myGameServerForm, game) -> {
            if (myGameServerForm.getType() == MyGameTypeEnum.SHOP.value()) { //暂时先弄商户的
                Optional<MyGame> shopGame = findShopGame(myGameServerForm.getShopId(), game.getId());
                if (shopGame.isPresent()) {
                    addExitGameInventory(shopGame.get());
                }else{
                    MyGame myGame = SetGameFormManager.toAddMyGame(myGameServerForm, form.getOptId());
                    mapper.insertSelective(myGame);
                }
            }else{
                MyGame myGame = SetGameFormManager.toAddMyGame(myGameServerForm, form.getOptId());
                mapper.insertSelective(myGame);
            }
        });
    }

    private void addExitGameInventory(MyGame myGame) {
        MyGame update = new MyGame();
        update.setMyGameId(myGame.getMyGameId());
        Integer inventory = myGame.getInventory();
        if (inventory == null) {
            inventory = 0;
        }
        update.setInventory(inventory + 1);
        update.setGmtModify(new Date());
        mapper.updateByPrimaryKeySelective(update);
    }

    @Transactional
    @Override
    public void delMyGame(SetGameForm form) {
        MyGameForm[] games = form.getGames();
        if (ArrayUtil.isEmpty(games)) {
            throw new RequestErrorException();
        }
        for (MyGameForm game : games) {
            Integer myGameId = game.getMyGameId();
            nonNull(myGameId);
            MyGame myGame = mapper.selectByPrimaryKey(myGameId);
            if (!myGame.getMemberId().equals(form.getOptId())) {
                throw new WikiException(WikiExceptionEnum.GAME_OPT_NO_AUTH);
            }
            if (myGame.getStatus() == StatusEnum.NORMAL.value()) {
                MyGame updateGame = new MyGame();
                updateGame.setMyGameId(myGameId);
                updateGame.setStatus(StatusEnum.DELETED.value());
                mapper.updateByPrimaryKeySelective(updateGame);
            }
        }
    }

    @Override
    public Page<MyGameVo> findMyGame(SearchMyGameQuery query) {
//        if (query.getMemberId() == null && query.getShopId() == null) {
//            query.setMemberId(query.getOptId());
//        }
        Page<MyGameVo> myGames = Pager.doPage(query, () -> mapper.searchMyGame(query));
        myGames.forEach(this::downloadUrlConverter);
        return myGames;
    }

    private void downloadUrlConverter(MyGameVo game) {
        String logo = game.getLogo();
        if (logo != null) {
            String toDownloadUrl = fileHelper.toDownloadUrl(logo);
            game.setLogo(toDownloadUrl);
        }
    }

    @Override
    @Transactional
    public void editHotGames(HotEditForm form) {
        Integer[] myGameIds = form.getMyGameIds();
        if (!ArrayUtil.isEmpty(myGameIds)) {
            for (Integer myGameId : myGameIds) {
                MyGame game = findById(myGameId);
                if (!game.getMemberId().equals(form.getMid())) {
                    throw new ServiceException(MYGAME_NOT_FOUND.errorCode(), MYGAME_NOT_FOUND.errorMsg());
                }
                MyGame myGame = new MyGame();
                myGame.setMyGameId(myGameId);
                myGame.setHot(form.getHot()? TrueOrFalseEnum.TRUE.value():TrueOrFalseEnum.FALSE.value());
                myGame.setGmtModify(new Date());
                mapper.updateByPrimaryKeySelective(myGame);
            }
        }
    }

    private MyGame findById(Integer myGameId) {
        MyGame myGame = mapper.selectByPrimaryKey(myGameId);
        if (myGame == null) {
            throw new ServiceException(MYGAME_NOT_FOUND.errorCode(), MYGAME_NOT_FOUND.errorMsg());
        }
        return myGame;

    }

    @Override
    public MyGame selectById(@NotNull Integer id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public Optional<MyGame> findMyGameWithRole(@NotNull Integer gameId, MyGameTypeEnum myGameType) {
        MyGame myGame = mapper.selectByPrimaryKey(gameId);
        if (myGame == null) {
            throw new WikiException(MYGAME_NOT_FOUND);
        }
        if (myGame.getType() != myGameType.value()) {
            return Optional.empty();
        }
        return Optional.of(myGame);
    }

    /**
     * 商铺如果不存在此桌游库存，则添加，否则返回此库存
     * @return 我的游戏库存
     */
    @Override
    public MyGame shopFindIfHasNotGameThenCreate(Integer shopId, Integer gameId, String optId) {
        MyGameExample example = new MyGameExample();
        example.createCriteria()
                .andShopIdEqualTo(shopId)
                .andGameIdEqualTo(gameId)
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        Optional<MyGame> existGameOptional = Pager.doSingleton(() -> mapper.selectByExample(example));
        if (existGameOptional.isPresent()) {
            return existGameOptional.get();
        } else {
            MyGame myGame = toAddShopGame(shopId, gameId, optId);
            myGame.setInventory(0);
            mapper.insertSelective(myGame);
            return myGame;
        }

    }

    @Override
    public Optional<MyGame> findShopGame(Integer shopId, Integer gameId) {
        MyGameExample example = new MyGameExample();
        example.createCriteria()
                .andShopIdEqualTo(shopId)
                .andGameIdEqualTo(gameId)
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        return Pager.doSingleton(() -> mapper.selectByExample(example));
    }

    @Override
    public void modifyInventory(@NotNull Integer id, @NotNull Integer num) {
        MyGame updateGame = new MyGame();
        updateGame.setMyGameId(id);
        updateGame.setInventory(num);
        mapper.modifyInventory(updateGame);
    }

    private void checkDataAndForEach(SetGameForm form, BiConsumer<MyGameServiceForm,Game> onLoapOperation) {
        ValidatorUtil.validate(form);

        MyGameForm[] games = form.getGames();
        if (ArrayUtil.isEmpty(games)) {
            throw new RequestErrorException();
        }
        for (MyGameForm game : games) {
            Integer gameId = game.getGameId();
            nonNull(gameId);
            Game dbGame = gameService.selectById(gameId);
            if (dbGame == null) {
                throw new WikiException(WikiExceptionEnum.WIKI_NOT_FOUND_EXCEPTION);
            }
            Byte type = form.getType();
            MyGameServiceForm serviceForm = new MyGameServiceForm();

            if (type == MyGameTypeEnum.SHOP.value()) {
                Integer shopId = form.getShopId();
                nonNull(shopId);
                shopService.isShopManager(shopId, form.getOptId()).orElseThrow(() -> new WikiException(WikiExceptionEnum.GAME_OPT_NO_AUTH));
                serviceForm.setShopId(shopId);
                serviceForm.setType(MyGameTypeEnum.SHOP.value());
            }else{
                serviceForm.setShopId(null);
                serviceForm.setType(MyGameTypeEnum.USER.value());
            }
            serviceForm.setMyGameForm(game);
            onLoapOperation.accept(serviceForm, dbGame);
        }
    }

}
